#ifndef __M_HOST_H__
#define __M_HOST_H__
#include "mq_exchange.hpp"
#include "mq_queue.hpp"
#include "mq_binding.hpp"
#include "mq_message.hpp"

namespace csjmq
{
    class VirtualHost
    {
    public:
        using ptr = std::shared_ptr<VirtualHost>;
        VirtualHost(const std::string &hostname, const std::string &basedir, const std::string &dbfile)
            : _hostname(hostname),
              emp(std::make_shared<ExchangeManager>(dbfile)),
              mqmp(std::make_shared<MsgQueueManager>(dbfile)),
              bmp(std::make_shared<BindingManager>(dbfile)),
              mmp(std::make_shared<MessageManager>(basedir))

        {
            // 获取所有的队列消息，通过队列名称恢复历史数据
            QueueMap qm = mqmp->allQueues();
            for (auto &it : qm)
            {
                mmp->initQueueMessage(it.first);
            }
        }

        bool declareExchange(const std::string &name, ExchangeType type,
                             bool durable, bool auto_delete,
                             const google::protobuf::Map<std::string, std::string> &args)
        {
            return emp->declareExchange(name, type, durable, auto_delete, args);
        }

        // 删除交换机的时候，需要将交换机相关的绑定信息也删除
        void deleteExchange(const std::string &ename)
        {
            bmp->removeExchangeBindings(ename);
            return emp->deleteExchange(ename);
        }

        bool declareQueue(const std::string &name, bool durable, bool exclusive, bool auto_delete,
                          const google::protobuf::Map<std::string, std::string> &args)
        {
            mmp->initQueueMessage(name);
            return mqmp->declareQueue(name, durable, exclusive, auto_delete, args);
        }

        // 删除队列的时候，相关的数据有两个：队列的消息，队列的绑定的信息
        void deleteQueue(const std::string &name)
        {
            bmp->removeQueueBindings(name); // 删除队列binding信息
            mmp->destroyQueueMessage(name); // 删除队列中的信息
            mqmp->deleteQueue(name);        // 数据库中删除队列本身
        }

        Exchange::ptr selectExchange(const std::string &ename)
        {
            return emp->selectExchange(ename);
        }

        // 绑定的时候，交换机/队列必须存在
        bool bind(const std::string &ename, const std::string &qname,
                  const std::string &key)
        {
            Exchange::ptr ep = emp->selectExchange(ename);
            if (ep == nullptr)
            {
                DLOG("进行绑定失败，交换机 %s 不存在", ename.c_str());
                return false;
            }

            MsgQueue::ptr mqp = mqmp->selectQueue(qname);
            if (mqp == nullptr)
            {
                DLOG("进行绑定失败，队列 %s 不存在", qname.c_str());
                return false;
            }

            return bmp->bind(ename, qname, key, ep->durable && mqp->durable);
        }

        bool unbind(const std::string &ename, const std::string &qname)
        {
            return bmp->unbind(ename, qname);
        }

        MsgQueueBindingMap getExchangeBindings(const std::string &ename)
        {
            return bmp->getExchangeBindings(ename);
        }

        bool BasicPublish(const std::string &qname, const BasicProperties *bp, const std::string body)
        {
            MsgQueue::ptr mqp = mqmp->selectQueue(qname);
            if (mqp == nullptr)
            {
                DLOG("发布消息失败，队列 %s 不存在", qname.c_str());
                return false;
            }
            return mmp->insert(qname, bp, body, mqp->durable);
        }

        MessagePtr BasicConsume(const std::string &qname)
        {
            return mmp->front(qname);
        }

        void BasicAck(const std::string &qname, const std::string &msg_id)
        {
            mmp->ack(qname, msg_id);
        }

        bool existsExchange(const std::string &ename)
        {
            return emp->exists(ename);
        }

        bool existsQueue(const std::string &qname)
        {
            return mqmp->exists(qname);
        }

        bool existsBinding(const std::string &ename, const std::string &qname)
        {
            return bmp->exists(ename, qname);
        }

        QueueMap allQueues()
        {
            return mqmp->allQueues();
        }

        void clear()
        {
            emp->clear();
            mqmp->clear();
            bmp->clear();
            mmp->clear();
        }

    private:
        std::string _hostname;
        ExchangeManager::ptr emp;
        MsgQueueManager::ptr mqmp;
        BindingManager::ptr bmp;
        MessageManager::ptr mmp;
    };

}

#endif